/*
 * @file main.cpp
 * @author zhangpeihao
 */

#include <gtest/gtest.h>
#include <zsystem/core/common/types.h>
#include <zsystem/core/common/log.h>
#include "utcase.h"


#define TEST_all                0

#define TEST_glog               0
#define TEST_assert             1
#define TEST_atomInt            0
#define TEST_mutex              0
#define TEST_timeStamp          0
#define TEST_array              0
#define TEST_ring               0
#define TEST_alloc              0
#define TEST_map                0
#define TEST_skipList           0
#define TEST_stdMap             0
#define TEST_malloc             0
#define TEST_timeUtil           0
#define TEST_timeUtil_value     0
#define TEST_timeUtil_across    0
#define TEST_thread             0
#define TEST_conditionVariable  0
#define TEST_stdQueue           0
#define TEST_stdList            0
#define TEST_evThread           0
#define TEST_evThreadPool       0
#define TEST_evhtp              0
#define TEST_tcpsocket          0
#define TEST_tcpconnection      0
#define TEST_repidjson          0
#define TEST_gflags             0
#define TEST_lua                0

#if TEST_all || TEST_glog

DECLARE_VOID_POINTER(test);
TEST_F(utcase, glog)
{
  DLOG(INFO) << "Debug info";
  Z_U16 i = 0X0102;
  EXPECT_EQ((Z_U16)(*((Z_U8*)&i)), (Z_U16)2);
  LOG(INFO) << "Test info log: sizeof(Z_U16) = " << sizeof(Z_U16);
  LOG_IF(INFO, i < 1) << "Should not been logging";
  LOG_IF(INFO, i > 1) << "Should been logging";

  Z_I16 arr[10];
  for(Z_I32 i = 0; i < 10; i++)
  {
    arr[i] = i+1;
    LOG(INFO) << "arr[" << i << "] = " << arr[i];
    LOG_EVERY_N(ERROR, 4) <<  "arr[" << i << "] = " << arr[i] << "; counter = " << google::COUNTER;
  }

  std::string str("test string");
  LOG(WARNING) << "Test warning log: std::string = " << str;
  LPtest p = (LPtest)&i;
  LOG(ERROR) << "Test error log: pointer = " << std::hex << p;
//  Z_U64 data(10234353632342524L);
//  ASSERT_DEATH({LOG(FATAL) << "Test fatal log: Z_U64 = " << data;}, "");

  VLOG(0) << "0) Test Vlog, should been logged";
  VLOG(1) << "1) Test Vlog, should not been logged";

  FLAGS_v = 3;
  VLOG(2) << "2) Test Vlog, should been logged";
  VLOG(3) << "3) Test Vlog, should been logged";
  VLOG(4) << "4) Test Vlog, should not been logged";


}
#endif

#if TEST_all || TEST_assert
#include <zsystem/core/common/assert.h>
class testAssertClassBase{
public:
  char c;
};
class testAssertClass : testAssertClassBase{
public:
  int i;
};
TEST_F(utcase, assert)
{
  Z_PTR data(Z_NULL);
  testAssertClass* c = reinterpret_cast<testAssertClass*>(data);
  Z_ASSERT(c == Z_NULL);
  data = (Z_PTR)12345;
  c = reinterpret_cast<testAssertClass*>(data);
  Z_ASSERT(c == (Z_PTR)12345);

  SCOPED_TRACE("Before Z_ASSERT(true)");
  Z_ASSERT(true);

  Z_BOOL bTrue(true);
  SCOPED_TRACE("Before Z_ASSERT(bTrue)");
  Z_ASSERT(bTrue);

  Z_U32 i100(100);
  SCOPED_TRACE("Before Z_ASSERT(i100 > 10)");
  Z_ASSERT(i100 > 10);

  SCOPED_TRACE("Before Z_ASSERT(i100)");
  Z_ASSERT(i100);

  Z_BOOL bFalse(false);
  Z_U32 i0(0);
#ifdef __DEBUG__
  SCOPED_TRACE("Before Z_ASSERT(false)");
  ASSERT_DEATH(Z_ASSERT(false), "");

  bFalse = false;
  SCOPED_TRACE("Before Z_ASSERT(bFalse)");
  ASSERT_DEATH(Z_ASSERT(bFalse), "");

  SCOPED_TRACE("Before Z_ASSERT(i0 > 10)");
  ASSERT_DEATH(Z_ASSERT(i0 > 10), "");

  i0 = 0;
  SCOPED_TRACE("Before Z_ASSERT(i0)");
  ASSERT_DEATH(Z_ASSERT(i0), "");
#endif

  SCOPED_TRACE("Before Z_ASSERT_ALL(false)");
  ASSERT_DEATH(Z_ASSERT_ALL(false), "");

  bFalse = false;
  SCOPED_TRACE("Before Z_ASSERT_ALL(bFalse)");
  ASSERT_DEATH(Z_ASSERT_ALL(bFalse), "");

  i0 = 0;
  SCOPED_TRACE("Before Z_ASSERT_ALL(i0 > 10)");
  ASSERT_DEATH(Z_ASSERT_ALL(i0 > 10), "");

  SCOPED_TRACE("Before Z_ASSERT_ALL(i0)");
  ASSERT_DEATH(Z_ASSERT_ALL(i0), "");

}
#endif

#if TEST_all || TEST_atomInt
#include <zsystem/core/common/lockfree.h>
template <typename T>
class atomIntTest : public ::testing::Test 
{
protected:
  zsystem::atomInt<T> _data;
};
TYPED_TEST_CASE_P(atomIntTest);
TYPED_TEST_P(atomIntTest, atomInt)
{
  TypeParam data;
  Z_ASSERT_ALIGN(&data, sizeof(data));
  EXPECT_EQ((const TypeParam)0, (const TypeParam)this->_data.get());
  EXPECT_EQ((const TypeParam)0, (const TypeParam)this->_data.set(10));
  EXPECT_EQ((const TypeParam)10, (const TypeParam)this->_data.get());
  EXPECT_EQ((const TypeParam)10, (const TypeParam)this->_data.add((const TypeParam)15));
  EXPECT_EQ((const TypeParam)25, (const TypeParam)this->_data.get());
  EXPECT_EQ((const TypeParam)25, (const TypeParam)this->_data.sub((const TypeParam)10));
  EXPECT_EQ((const TypeParam)15, (const TypeParam)this->_data.get());
  EXPECT_EQ((const TypeParam)15, (const TypeParam)this->_data.bitAnd((TypeParam)0X6LL));
  EXPECT_EQ((const TypeParam)6, (const TypeParam)this->_data.get());
  EXPECT_EQ((const TypeParam)6, (const TypeParam)this->_data.bitOr((TypeParam)0X9LL));
  EXPECT_EQ((const TypeParam)15, (const TypeParam)this->_data.get());


  (this->_data).operator++();
  EXPECT_EQ((const TypeParam)16, (const TypeParam)this->_data.get());
  (this->_data).operator--();
  EXPECT_EQ((const TypeParam)15, (const TypeParam)this->_data.get());
  EXPECT_EQ((const TypeParam)15, (const TypeParam)this->_data.casSet(16, 30));
  EXPECT_EQ((const TypeParam)15, (const TypeParam)this->_data.get());
  EXPECT_EQ((const TypeParam)15, (const TypeParam)this->_data.casSet(15, 30));
  EXPECT_EQ((const TypeParam)30, (const TypeParam)this->_data.get());

  // static cas
  data = 10;
  EXPECT_EQ((const TypeParam)10, (const TypeParam)zsystem::atomInt<TypeParam>::casSet(&data, 10, 20));
  EXPECT_EQ((const TypeParam)20, data);
}


REGISTER_TYPED_TEST_CASE_P(atomIntTest, atomInt);
typedef ::testing::Types<Z_U8, Z_U16, Z_U32, Z_U64, Z_I8, Z_I16, Z_I32, Z_I64> atomTypes;
INSTANTIATE_TYPED_TEST_CASE_P(AtomInt, atomIntTest, atomTypes);

template <typename T>
class atomIntTestSign : public ::testing::Test 
{
protected:
  zsystem::atomInt<T> _data;
};
TYPED_TEST_CASE_P(atomIntTestSign);
TYPED_TEST_P(atomIntTestSign, atomIntSign)
{
  TypeParam data;
  Z_ASSERT_ALIGN(&data, sizeof(data));
  EXPECT_EQ((const TypeParam)0, (const TypeParam)this->_data.get());
  EXPECT_EQ((const TypeParam)0, (const TypeParam)this->_data.set(-10));
  EXPECT_EQ((const TypeParam)-10, (const TypeParam)this->_data.get());
  EXPECT_EQ((const TypeParam)-10, (const TypeParam)this->_data.add((const TypeParam)15));
  EXPECT_EQ((const TypeParam)5, (const TypeParam)this->_data.get());
  EXPECT_EQ((const TypeParam)5, (const TypeParam)this->_data.sub((const TypeParam)10));
  EXPECT_EQ((const TypeParam)-5, (const TypeParam)this->_data.get());
  (this->_data).operator++();
  EXPECT_EQ((const TypeParam)-4, (const TypeParam)this->_data.get());
  (this->_data).operator--();
  EXPECT_EQ((const TypeParam)-5, (const TypeParam)this->_data.get());
  EXPECT_EQ((const TypeParam)-5, (const TypeParam)this->_data.casSet(-6, 30));
  EXPECT_EQ((const TypeParam)-5, (const TypeParam)this->_data.get());
  EXPECT_EQ((const TypeParam)-5, (const TypeParam)this->_data.casSet(-5, -1));
  EXPECT_EQ((const TypeParam)-1, (const TypeParam)this->_data.get());

  // static cas
  data = -2;
  EXPECT_EQ((const TypeParam)-2, (const TypeParam)zsystem::atomInt<TypeParam>::casSet(&data, -2, -3));
  EXPECT_EQ((const TypeParam)-3, (const TypeParam)zsystem::atomInt<TypeParam>::get(&data));
  EXPECT_EQ((const TypeParam)-3, (const TypeParam)zsystem::atomInt<TypeParam>::set(&data, 5));
  EXPECT_EQ((const TypeParam)5, (const TypeParam)zsystem::atomInt<TypeParam>::inc(&data));
  EXPECT_EQ((const TypeParam)6, (const TypeParam)zsystem::atomInt<TypeParam>::dec(&data));
  EXPECT_EQ((const TypeParam)5, (const TypeParam)zsystem::atomInt<TypeParam>::add(&data, 10));

  EXPECT_EQ((const TypeParam)15, (const TypeParam)zsystem::atomInt<TypeParam>::bitAnd(&data, (TypeParam)0X6LL));
  EXPECT_EQ((const TypeParam)6, (const TypeParam)zsystem::atomInt<TypeParam>::get(&data));
  EXPECT_EQ((const TypeParam)6, (const TypeParam)zsystem::atomInt<TypeParam>::bitOr(&data, (TypeParam)0X9LL));
  EXPECT_EQ((const TypeParam)15, (const TypeParam)zsystem::atomInt<TypeParam>::get(&data));

  EXPECT_EQ((const TypeParam)15, (const TypeParam)zsystem::atomInt<TypeParam>::sub(&data, 25));
  EXPECT_EQ((const TypeParam)-10, (const TypeParam)zsystem::atomInt<TypeParam>::get(&data));
}

REGISTER_TYPED_TEST_CASE_P(atomIntTestSign, atomIntSign);
typedef ::testing::Types<Z_I8, Z_I16, Z_I32, Z_I64> atomTypesSign;
INSTANTIATE_TYPED_TEST_CASE_P(AtomIntSign, atomIntTestSign, atomTypesSign);

template <typename T>
class atomUnsigendIntTest : public atomIntTest<T>
{
};
TYPED_TEST_CASE_P(atomUnsigendIntTest);
TYPED_TEST_P(atomUnsigendIntTest, unsignedInt)
{
  Z_U8 typeSize = sizeof(TypeParam);
  TypeParam t1(1), t2(1);
  this->_data.set((const TypeParam)1);
  for(Z_U8 i = 0; i < typeSize; i++)
  {
    t2 = t1;
    t1 = t1 << 1;
    EXPECT_GT(t1, t2);
    EXPECT_EQ(t2, (const TypeParam)this->_data.casSet(t2, t1));
  }
}

REGISTER_TYPED_TEST_CASE_P(atomUnsigendIntTest, unsignedInt);
typedef ::testing::Types<Z_U8, Z_U16, Z_U32, Z_U64> UnsignedTypes;
INSTANTIATE_TYPED_TEST_CASE_P(UnsignedInt, atomUnsigendIntTest, UnsignedTypes);

template <typename T>
class atomSigendIntTest : public atomIntTest<T>
{
};
TYPED_TEST_CASE_P(atomSigendIntTest);
TYPED_TEST_P(atomSigendIntTest, signedInt)
{
  Z_U8 typeSize = sizeof(TypeParam);
  TypeParam t1(1), t2(1);
  this->_data.set((const TypeParam)1);
  for(Z_U8 i = 0; i < typeSize - 1; i++)
  {
    t2 = t1;
    t1 = t1 << 1;
    EXPECT_GT(t1, t2);
    EXPECT_EQ(t2, (const TypeParam)this->_data.casSet(t2, t1));
  }
  t1 = t2 = -1;
  this->_data.set(t1);
  for(Z_U8 i = 0; i < typeSize - 1; i++)
  {
    t2 = t1;
    t1 = t1 * 2;
    EXPECT_LT(t1, t2);
    EXPECT_EQ(t2, (const TypeParam)this->_data.casSet(t2, t1));
  }

}
REGISTER_TYPED_TEST_CASE_P(atomSigendIntTest, signedInt);
typedef ::testing::Types<Z_I8, Z_I16, Z_I32, Z_I64> SignedTypes;
INSTANTIATE_TYPED_TEST_CASE_P(signedInt, atomSigendIntTest, SignedTypes);

#endif

#if TEST_all || TEST_mutex
#include <zsystem/core/common/mutex.h>
template <typename T>
class lockTest : public ::testing::Test 
{
protected:
};
TYPED_TEST_CASE_P(lockTest);
TYPED_TEST_P(lockTest, lock)
{
  TypeParam lockObj;
  for(int i = 0; i < 1000; i++)
  {
    SCOPED_TRACE("Before lock()");
    lockObj.lock();
    SCOPED_TRACE("Before trylock()");
    EXPECT_FALSE(lockObj.tryLock());
    SCOPED_TRACE("Before unlock()");
    lockObj.unlock();
    SCOPED_TRACE("Before trylock()");
    EXPECT_TRUE(lockObj.tryLock()) << "i = " << i;
    SCOPED_TRACE("Before unlock()");
    lockObj.unlock();
    SCOPED_TRACE("After unlock()");

    SCOPED_TRACE("Before lock() again");
    lockObj.lock();
    SCOPED_TRACE("Before trylock() again");
    EXPECT_FALSE(lockObj.tryLock());
    SCOPED_TRACE("Before unlock() again");
    lockObj.unlock();
  }
}

REGISTER_TYPED_TEST_CASE_P(lockTest, lock);
typedef ::testing::Types<zsystem::mutexLock, zsystem::spinLock, zsystem::fifoSpinLock> lockTypes;
INSTANTIATE_TYPED_TEST_CASE_P(LockTest, lockTest, lockTypes);

/////////////////////////////////////////////////////////////////
template <typename T>
class rwlockTest : public ::testing::Test 
{
protected:
};
TYPED_TEST_CASE_P(rwlockTest);
TYPED_TEST_P(rwlockTest, rwlock)
{

  TypeParam lockObj;

  SCOPED_TRACE("Before readlock()");
  lockObj.readLock();

  SCOPED_TRACE("Before tryWriteLock()");
  EXPECT_FALSE(lockObj.tryWriteLock());

  SCOPED_TRACE("Before tryReadLock()");
  EXPECT_TRUE(lockObj.tryReadLock());

  SCOPED_TRACE("Before readUnlock()");
  lockObj.readUnlock();

  SCOPED_TRACE("Before tryWriteLock()");
  EXPECT_FALSE(lockObj.tryWriteLock());

  SCOPED_TRACE("Before tryReadLock()");
  EXPECT_TRUE(lockObj.tryReadLock());

  SCOPED_TRACE("Before readUnlock()");
  lockObj.readUnlock();

  SCOPED_TRACE("Before readUnlock()");
  lockObj.readUnlock();

  SCOPED_TRACE("Before writeLock()");
  lockObj.writeLock();

  SCOPED_TRACE("Before tryWriteLock()");
  EXPECT_FALSE(lockObj.tryWriteLock());

  SCOPED_TRACE("Before tryReadLock()");
  EXPECT_FALSE(lockObj.tryReadLock());

  SCOPED_TRACE("Before writeUnlock()");
  lockObj.writeUnlock();
}

REGISTER_TYPED_TEST_CASE_P(rwlockTest, rwlock);
typedef ::testing::Types<zsystem::mutexRWLock, zsystem::spinRWLock> rwlockTypes;
INSTANTIATE_TYPED_TEST_CASE_P(RWLockTest, rwlockTest, rwlockTypes);

///////////////////////////////////////////////////////
template <typename T>
class guardTest : public ::testing::Test 
{
protected:
};
TYPED_TEST_CASE_P(guardTest);
TYPED_TEST_P(guardTest, guard)
{
  SCOPED_TRACE("Before function guard");
  TypeParam lock;

  {
    SCOPED_TRACE("Before block guard");
    zsystem::guard<TypeParam> blockGuard(lock);
    SCOPED_TRACE("Exit block");
  }
  SCOPED_TRACE("Exit function");
}

REGISTER_TYPED_TEST_CASE_P(guardTest, guard);
typedef ::testing::Types<zsystem::mutexLock, zsystem::spinLock, zsystem::fifoSpinLock> guardTypes;
INSTANTIATE_TYPED_TEST_CASE_P(GuardTest, guardTest, guardTypes);


///////////////////////////////////////////////////////
template <typename T>
class locktTest : public ::testing::Test 
{
public:
  locktTest():testing::Test(), _id((T)0), _data(0){};
protected:
  T _id;
  Z_U8 _data;
};
TYPED_TEST_CASE_P(locktTest);
TYPED_TEST_P(locktTest, lockt)
{
  this->_id = 5;
  this->_data = 10;
  zsystem::lock_t<locktTest<TypeParam>*, TypeParam, zsystem::spinLock> dataWithLock(5, this);

  EXPECT_FALSE(dataWithLock.lock(6));
  EXPECT_FALSE(dataWithLock.tryLock(6));
  EXPECT_TRUE(dataWithLock.lock(5));
  EXPECT_FALSE(dataWithLock.tryLock(5));
  dataWithLock.unlock();
  EXPECT_TRUE(dataWithLock.tryLock(5));

  locktTest<TypeParam>* dataValue = dataWithLock.getData();
  Z_PTR_TYPE THIS_VALUE = (Z_PTR_TYPE)this;
  EXPECT_EQ(THIS_VALUE, (Z_PTR_TYPE)dataValue);

  dataWithLock.setData(NULL);
  dataValue = dataWithLock.getData();
  EXPECT_EQ(NULL, dataValue);
  dataWithLock.unlock();

  EXPECT_TRUE(dataWithLock.lock(5)); // Lock for distruct
}

REGISTER_TYPED_TEST_CASE_P(locktTest, lockt);
typedef ::testing::Types<Z_U8, Z_U16, Z_U32, Z_U64, Z_I8, Z_I16, Z_I32, Z_I64> locktTypes;
INSTANTIATE_TYPED_TEST_CASE_P(LocktTest, locktTest, locktTypes);

///////////////////////////////////////////////////////
template <typename T>
class locktTest2 : public ::testing::Test 
{
};
TYPED_TEST_CASE_P(locktTest2);
class lockDataKlass{
public:
  Z_U32 _key;
  Z_U32 _data;
};
TYPED_TEST_P(locktTest2, lockt2)
{
  lockDataKlass data;
  data._key = 5;
  data._data = 10;
  zsystem::lock_t<lockDataKlass*, Z_U32, TypeParam> dataWithLock(5, &data);

  EXPECT_FALSE(dataWithLock.lock(6));
  EXPECT_FALSE(dataWithLock.tryLock(6));
  EXPECT_TRUE(dataWithLock.lock(5));
  EXPECT_FALSE(dataWithLock.tryLock(5));
  dataWithLock.unlock();
  EXPECT_TRUE(dataWithLock.tryLock(5));

  lockDataKlass* dataValue = dataWithLock.getData();
  EXPECT_EQ(&data, (Z_PTR)dataValue);

  dataWithLock.setData(NULL);
  dataValue = dataWithLock.getData();
  EXPECT_EQ(NULL, dataValue);
  dataWithLock.unlock();

  EXPECT_TRUE(dataWithLock.lock(5)); // Lock for distruct
}

REGISTER_TYPED_TEST_CASE_P(locktTest2, lockt2);
typedef ::testing::Types<zsystem::fifoSpinLock, zsystem::spinLock, zsystem::mutexLock> locktTypes2;
INSTANTIATE_TYPED_TEST_CASE_P(LocktTest2, locktTest2, locktTypes2);

///////////////////////////////////////////////////////
template <typename T>
class rwlocktTest : public ::testing::Test 
{
public:
  rwlocktTest():testing::Test(), _id((T)0), _data(0){};
protected:
  T _id;
  Z_U8 _data;
};
TYPED_TEST_CASE_P(rwlocktTest);
TYPED_TEST_P(rwlocktTest, rwlockt)
{
  this->_id = 5;
  this->_data = 10;
  zsystem::rwlock_t<rwlocktTest<TypeParam>*, TypeParam, zsystem::spinRWLock> dataWithLock(5, this);

  EXPECT_FALSE(dataWithLock.readLock(6));
  EXPECT_FALSE(dataWithLock.writeLock(6));
  EXPECT_TRUE(dataWithLock.readLock(5));
  EXPECT_TRUE(dataWithLock.readLock(5));
  EXPECT_TRUE(dataWithLock.tryReadLock(5));
  dataWithLock.readUnlock();
  dataWithLock.readUnlock();

  rwlocktTest<TypeParam>* dataValue = dataWithLock.getData();
  Z_PTR THIS_VALUE = (Z_PTR)this;
  EXPECT_EQ(THIS_VALUE, (Z_PTR)dataValue);

  dataWithLock.setData(NULL);
  dataValue = dataWithLock.getData();
  EXPECT_EQ(NULL, dataValue);
  dataWithLock.readUnlock();

  dataWithLock.writeLock(5); // Lock for distruct
}

REGISTER_TYPED_TEST_CASE_P(rwlocktTest, rwlockt);
typedef ::testing::Types<Z_U8, Z_U16, Z_U32, Z_U64, Z_I8, Z_I16, Z_I32, Z_I64> rwlocktTypes;
INSTANTIATE_TYPED_TEST_CASE_P(rwLocktTest, rwlocktTest, rwlocktTypes);

///////////////////////////////////////////////////////
template <typename T>
class rwlocktTest2 : public ::testing::Test 
{
};
TYPED_TEST_CASE_P(rwlocktTest2);
TYPED_TEST_P(rwlocktTest2, rwlockt2)
{
  lockDataKlass data;
  data._key = 5;
  data._data = 10;
  zsystem::rwlock_t<lockDataKlass*, Z_U32, TypeParam> dataWithLock(5, &data);

  EXPECT_FALSE(dataWithLock.readLock(6));
  EXPECT_FALSE(dataWithLock.writeLock(6));
  EXPECT_TRUE(dataWithLock.readLock(5));
  EXPECT_TRUE(dataWithLock.readLock(5));
  EXPECT_TRUE(dataWithLock.tryReadLock(5));
  dataWithLock.readUnlock();
  dataWithLock.readUnlock();

  lockDataKlass* dataValue = dataWithLock.getData();
  EXPECT_EQ(&data, (Z_PTR)dataValue);

  dataWithLock.setData(NULL);
  dataValue = dataWithLock.getData();
  EXPECT_EQ(NULL, dataValue);
  dataWithLock.readUnlock();

  dataWithLock.writeLock(5); // Lock for distruct
}

REGISTER_TYPED_TEST_CASE_P(rwlocktTest2, rwlockt2);
typedef ::testing::Types<zsystem::spinRWLock, zsystem::mutexRWLock> rwlocktTypes2;
INSTANTIATE_TYPED_TEST_CASE_P(rwLocktTest2, rwlocktTest2, rwlocktTypes2);

#endif

#if TEST_all || TEST_timeStamp
#include <zsystem/core/common/timestamp.h>
TEST_F(utcase, staticTimestamp)
{
  zsystem::timestamp startAt = zsystem::baseTimestamp::now();
  std::cout << "stateAt: 0x" << std::hex << startAt << std::dec << ", " << startAt << std::endl;
  zsystem::staticTimestamp st;
  EXPECT_GT((zsystem::timestamp)st, (zsystem::timestamp)0x122ebfa7d0baf4f0LL);
  EXPECT_GE((zsystem::timestamp)st, startAt);

  double second = zsystem::baseTimestamp::toSecond(startAt);
  double milliSecond = zsystem::baseTimestamp::toMilliSecond(startAt);
  double microSecond = zsystem::baseTimestamp::toMicroSecond(startAt);
  double nanoSecond = zsystem::baseTimestamp::toNanoSecond(startAt);
  std::cout << std::fixed << std::setfill(' ');
  std::cout << "second =      " << std::setw(30) << std::setprecision(8) << second << std::endl;
  std::cout << "milliSecond = " << std::setw(30) << std::setprecision(8) << milliSecond << std::endl;
  std::cout << "microSecond = " << std::setw(30) << std::setprecision(8) << microSecond << std::endl;
  std::cout << "nanoSecond =  " << std::setw(30) << std::setprecision(8) << nanoSecond << std::endl;
  EXPECT_DOUBLE_EQ((double)startAt, nanoSecond);
  EXPECT_DOUBLE_EQ((double)startAt, (microSecond*1000));
  EXPECT_DOUBLE_EQ((double)startAt, (milliSecond*1000000));
  EXPECT_DOUBLE_EQ((double)startAt, (second*1000000000));
}
#endif

#if TEST_all || TEST_array
#include <zsystem/core/common/array.h>
template <typename T>
class arrayTest : public ::testing::Test 
{
public:
protected:
};

TYPED_TEST_CASE_P(arrayTest);
TYPED_TEST_P(arrayTest, array)
{
  {
    zsystem::array<TypeParam>* pArray;
    pArray = new zsystem::array<TypeParam>(1);
    EXPECT_EQ((Z_U32)1, pArray->getNumber());
    EXPECT_EQ((Z_U32)(Z_MAX(SYS_ALIGN, sizeof(TypeParam))), pArray->getItemSize());
    TypeParam* item = pArray->get(0);
    *item = 1;
    const TypeParam* itemConst = pArray->get(0);
    EXPECT_EQ((TypeParam)1, *itemConst);
#ifdef __DEBUG__
    ASSERT_DEATH(pArray->get(1), "");
#else
    EXPECT_TRUE(NULL == pArray->get(1));
#endif
    TypeParam& item2 = (*pArray)[0];
    EXPECT_EQ((TypeParam)1, item2);
    const TypeParam& item2Const = (*pArray)[0];
    EXPECT_EQ((TypeParam)1, item2Const);
    delete pArray;
  }
  {
    zsystem::array<TypeParam>* pArray;
    pArray = new zsystem::array<TypeParam>(10000);
    EXPECT_EQ((Z_U32)10000, pArray->getNumber());
    EXPECT_EQ((Z_U32)(Z_MAX(SYS_ALIGN, sizeof(TypeParam))), pArray->getItemSize());

    TypeParam* item = pArray->get(0);
    *item = 1;
    const TypeParam* itemConst = pArray->get(0);
    EXPECT_EQ((TypeParam)1, *itemConst);
    TypeParam& item2 = (*pArray)[0];
    EXPECT_EQ((TypeParam)1, item2);
    const TypeParam& item2Const = (*pArray)[0];
    EXPECT_EQ((TypeParam)1, item2Const);

    TypeParam* item9999 = pArray->get(9999);
    *item9999 = 1;
    const TypeParam* item9999Const = pArray->get(9999);
    EXPECT_EQ((TypeParam)1, *item9999Const);
    TypeParam& item9999_2 = (*pArray)[9999];
    EXPECT_EQ((TypeParam)1, item9999_2);
    const TypeParam& item99999Const_2 = (*pArray)[9999];
    EXPECT_EQ((TypeParam)1, item99999Const_2);

#ifdef __DEBUG__
    ASSERT_DEATH(pArray->get(10000), "");
#else
    EXPECT_TRUE(NULL == pArray->get(10000));
#endif

    delete pArray;
  }
}

REGISTER_TYPED_TEST_CASE_P(arrayTest, array);
typedef ::testing::Types<Z_U8, Z_U16, Z_U32, Z_U64, Z_I8, Z_I16, Z_I32, Z_I64, float, double> arrayTypes;
INSTANTIATE_TYPED_TEST_CASE_P(ArrayTest, arrayTest, arrayTypes);

struct test_array_9{
  Z_U8 filling[9];
};

TEST(ArrayTest, arrayCommon)
{
  ASSERT_DEATH((new zsystem::array<Z_U32,sizeof(Z_U32)>(0)), "");
  {
    zsystem::array<test_array_9,sizeof(test_array_9)> a1(2);
    EXPECT_EQ((Z_U32)9, a1.getItemSize());
    Z_U64 p1 = (Z_U64)(a1.get(0));
    Z_U64 p2 = (Z_U64)(a1.get(1));
    EXPECT_EQ((Z_U32)9, (Z_U32)(p2 - p1));
  }
  {
    zsystem::array<test_array_9, 4> a2(2);
    EXPECT_EQ((Z_U32)12, a2.getItemSize());
    Z_U64 p1 = (Z_U64)(a2.get(0));
    Z_U64 p2 = (Z_U64)(a2.get(1));
    EXPECT_EQ((Z_U32)12, (Z_U32)(p2 - p1));
  }
  {
    zsystem::array<test_array_9, 8> a2(2);
    EXPECT_EQ((Z_U32)16, a2.getItemSize());
    Z_U64 p1 = (Z_U64)(a2.get(0));
    Z_U64 p2 = (Z_U64)(a2.get(1));
    EXPECT_EQ((Z_U32)16, (Z_U32)(p2 - p1));
  }
  {
    zsystem::array<test_array_9, 16> a2(2);
    EXPECT_EQ((Z_U32)16, a2.getItemSize());
    Z_U64 p1 = (Z_U64)(a2.get(0));
    Z_U64 p2 = (Z_U64)(a2.get(1));
    EXPECT_EQ((Z_U32)16, (Z_U32)(p2 - p1));
  }
}

#endif

#if TEST_all || TEST_ring
#include <zsystem/core/common/ring.h>

#define RING_SIZE 1000

TEST(RingTest, ring)
{
#ifdef __DEBUG__
  ASSERT_DEATH((new zsystem::pointerRing(0)), "");
  ASSERT_DEATH((new zsystem::pointerRing(100, 0)), "");
#endif
  {
    zsystem::pointerRing pr(2);
    EXPECT_EQ((Z_U32)2, pr.getSize());
    EXPECT_EQ((Z_U32)SYS_ALIGN, pr.getItemSize());
    EXPECT_EQ((Z_U32)0, pr.getItemNumber());

    Z_PTR p1 = 0;
    EXPECT_FALSE(pr.pop(p1));
#ifdef __DEBUG__
    ASSERT_DEATH(pr.push(p1),"");
#endif
#ifdef __RELEASE__
    EXPECT_FALSE(pr.push(p1));
#endif
    p1 = (Z_PTR)&pr;
    EXPECT_TRUE(pr.push(p1));
    EXPECT_EQ((Z_U32)1, pr.getItemNumber());

    Z_PTR p2 = &p1;
    EXPECT_TRUE(pr.push(p2));
    EXPECT_EQ((Z_U32)2, pr.getItemNumber());

    Z_PTR p3 = &p2;
    EXPECT_FALSE(pr.push(p3));
    EXPECT_EQ((Z_U32)2, pr.getItemNumber());
    
    Z_PTR a1 = 0;
    EXPECT_TRUE(pr.pop(a1));
    EXPECT_EQ(p1, a1);
    EXPECT_EQ((Z_U32)1, pr.getItemNumber());
    Z_PTR a2 = 0;
    EXPECT_TRUE(pr.pop(a2));
    EXPECT_EQ(p2, a2);
    EXPECT_EQ((Z_U32)0, pr.getItemNumber());
    Z_PTR a3 = 0;
    EXPECT_FALSE(pr.pop(a2));
    EXPECT_EQ((Z_U32)0, pr.getItemNumber());
  }
}

#endif


#if TEST_all || TEST_alloc
#include <zsystem/core/common/alloc.h>

class allocTestBasic{
public:
  allocTestBasic(int i = 0){}
  allocTestBasic(const allocTestBasic& other){}
  int i[4];
  char c;
};

TEST(allocTest, basic)
{
  EXPECT_EQ(8, Z_SYS_ALIGN_SIZE(Z_U64));
#ifdef __WIN32__
  EXPECT_EQ(4, Z_SYS_ALIGN_SIZE(Z_U32));
  EXPECT_EQ(4, Z_SYS_ALIGN_SIZE(Z_U16));
  EXPECT_EQ(4, Z_SYS_ALIGN_SIZE(Z_U8));

  EXPECT_EQ(20, Z_SYS_ALIGN_SIZE(allocTestBasic));
#else
  EXPECT_EQ(8, Z_SYS_ALIGN_SIZE(Z_U32));
  EXPECT_EQ(8, Z_SYS_ALIGN_SIZE(Z_U16));
  EXPECT_EQ(8, Z_SYS_ALIGN_SIZE(Z_U8));

  EXPECT_EQ(24, Z_SYS_ALIGN_SIZE(allocTestBasic));
#endif
}

template <typename T>
class allocTest : public ::testing::Test 
{
public:
protected:
};

#define BUFFER_SIZE 1000

TYPED_TEST_CASE_P(allocTest);
TYPED_TEST_P(allocTest, alloc)
{
  {
    zsystem::objectAlloc<TypeParam> qb(BUFFER_SIZE);
    EXPECT_EQ((Z_U32)BUFFER_SIZE, qb.getMaxSize());
    EXPECT_EQ((Z_U32)0, qb.getAllocatedNumber());
    TypeParam* data[BUFFER_SIZE];
    for(int i = 0; i < BUFFER_SIZE; i++)
    {
      data[i] = Z_NULL;
      data[i] = qb.allocate();
      EXPECT_TRUE(data[i] != Z_NULL);
      EXPECT_EQ((Z_U32)(i+1), qb.getAllocatedNumber());
    }
    EXPECT_TRUE(Z_NULL == qb.allocate());
    for(int i = 0; i < BUFFER_SIZE; i++)
    {
      qb.free(data[i]);
      EXPECT_EQ((Z_U32)((BUFFER_SIZE - 1) - i), qb.getAllocatedNumber());
    }
  }

  {
    zsystem::stdAllocator<TypeParam> sa;
    typename zsystem::stdAllocator<TypeParam>::pointer p = sa.allocate(5);
    ASSERT_TRUE(p != Z_NULL);
    TypeParam other(100);
    sa.construct(p, other);
    TypeParam* pObj = reinterpret_cast<TypeParam*>(p);
    typename zsystem::stdAllocator<TypeParam>::pointer p1 = sa.address(*pObj);
    ASSERT_TRUE(p1 != Z_NULL);
    ASSERT_TRUE(p1 == p);

    typename zsystem::stdAllocator<TypeParam>::const_pointer p2 = sa.const_address(*pObj);
    ASSERT_TRUE(p2 != Z_NULL);
    ASSERT_TRUE(p2 == p);

    EXPECT_EQ(USHRT_MAX, sa.max_size()) << "sizeof(TypeParam) = " << sizeof(TypeParam); 
    sa.destroy(p);
    sa.deallocate(p, 5);

  }
}

REGISTER_TYPED_TEST_CASE_P(allocTest, alloc);
typedef ::testing::Types<Z_U8, Z_U16, Z_U32, Z_U64, Z_I8, Z_I16, Z_I32, Z_I64, float, double, allocTestBasic> allocTypes;
INSTANTIATE_TYPED_TEST_CASE_P(AllocTest, allocTest, allocTypes);

#endif

#if TEST_all || TEST_map
#include <zsystem/core/common/map.h>
template <typename T>
class listTest : public ::testing::Test 
{
public:
protected:
};

#define LIST_SIZE 10

TYPED_TEST_CASE_P(listTest);
TYPED_TEST_P(listTest, list)
{
  {
    zsystem::casListBasedSet<TypeParam> ll(LIST_SIZE);
    //typedef zsystem::casListBasedSet<TypeParam>::iterator testIterator;
    EXPECT_EQ((Z_U32)LIST_SIZE, ll.getMaxSize());
    EXPECT_EQ((Z_U32)0, ll.getNumber());

    for(int i = 0; i < LIST_SIZE; i++)
    {
#ifdef __DEBUG__
      ASSERT_DEATH(ll.insert((TypeParam)i, (Z_PTR)(i * 8 + 1)), "");
#else
      EXPECT_FALSE(ll.insert((TypeParam)i, (Z_PTR)((i * 8 + 1))));
#endif
      EXPECT_TRUE(ll.insert((TypeParam)i, (Z_PTR)((i + 1) * 8)));
      EXPECT_FALSE(ll.insert((TypeParam)i, (Z_PTR)((i + 1) * 16)));
    }

    Z_PTR data(Z_NULL);
    for(int i = 0; i < LIST_SIZE; i++)
    {
      data = Z_NULL;
      EXPECT_TRUE(ll.lookup((TypeParam)i, data));
      EXPECT_EQ((Z_PTR_TYPE)(i + 1) * 8, (Z_PTR_TYPE)data);
      data = Z_NULL;
      EXPECT_FALSE(ll.lookup((TypeParam)(i + LIST_SIZE), data));
    }

    Z_PTR_TYPE it = ll.begin();
    Z_U32 i = 0;
    TypeParam key((TypeParam)0);
    while(it != ll.end())
    {
      EXPECT_TRUE(ll.get(it, key, data));
      EXPECT_EQ((Z_PTR_TYPE)(i + 1) * 8, (Z_PTR_TYPE)data);
      EXPECT_EQ(i, (Z_U32)key);
      it = ll.next(it);
      i++;
    }

    EXPECT_EQ((Z_U32)LIST_SIZE, i);

    EXPECT_FALSE(ll.get(Z_NULL, key, data));

    LOG(INFO) << "list: ";
    LOG(INFO) << ll;

    for(int i = 0; i < LIST_SIZE; i++)
    {
      data = Z_NULL;
      EXPECT_FALSE(ll.remove((TypeParam)(i + LIST_SIZE), data));
      EXPECT_TRUE(ll.remove((TypeParam)i, data));
      EXPECT_EQ((Z_PTR_TYPE)(i + 1) * 8, (Z_PTR_TYPE)data);
      data = Z_NULL;
      EXPECT_FALSE(ll.remove((TypeParam)i, data));
    }
  }
}

REGISTER_TYPED_TEST_CASE_P(listTest, list);
typedef ::testing::Types<Z_U8, Z_U16, Z_U32, Z_U64, Z_I8, Z_I16, Z_I32, Z_I64> listTypes;
INSTANTIATE_TYPED_TEST_CASE_P(ListTest, listTest, listTypes);

#endif


#if TEST_all || TEST_skipList
#include <zsystem/core/common/map.h>
template <typename T>
class skiplistTest : public ::testing::Test 
{
public:
protected:
};

#define LIST_SIZE 10

TYPED_TEST_CASE_P(skiplistTest);
TYPED_TEST_P(skiplistTest, skiplist)
{
  {
    zsystem::casSkipList<TypeParam> sl(LIST_SIZE);
    EXPECT_EQ((Z_U32)LIST_SIZE, sl.getMaxSize());
    EXPECT_EQ((Z_U32)0, sl.getNumber());

    for(int i = 0; i < LIST_SIZE; i++)
    {
#ifdef __DEBUG__
      ASSERT_DEATH(sl.insert((TypeParam)i, (Z_PTR)(i * 8 + 1)), "");
#else
      EXPECT_FALSE(sl.insert((TypeParam)i, (Z_PTR)((i * 8 + 1))));
#endif
      EXPECT_TRUE(sl.insert((TypeParam)i, (Z_PTR)((i + 1) * 8)));
      EXPECT_FALSE(sl.insert((TypeParam)i, (Z_PTR)((i + 1) * 16)));
    }

    Z_PTR data(Z_NULL);
    for(int i = 0; i < LIST_SIZE; i++)
    {
      data = Z_NULL;
      EXPECT_TRUE(sl.lookup((TypeParam)i, data));
      EXPECT_EQ((Z_PTR_TYPE)(i + 1) * 8, (Z_PTR_TYPE)data);
      data = Z_NULL;
      EXPECT_FALSE(sl.lookup((TypeParam)(i + LIST_SIZE), data));
    }

    Z_PTR_TYPE it = sl.begin();
    Z_U32 i = 0;
    TypeParam key((TypeParam)0);
    while(it != Z_NULL)
    {
      EXPECT_TRUE(sl.get(it, key, data));
      EXPECT_EQ((Z_PTR_TYPE)(i + 1) * 8, (Z_PTR_TYPE)data);
      EXPECT_EQ(i, (Z_U32)key);
      it = sl.next(it);
      i++;
    }

    EXPECT_EQ((Z_U32)LIST_SIZE, i);

    EXPECT_FALSE(sl.get(Z_NULL, key, data));

    LOG(INFO) << "list: ";
    LOG(INFO) << sl;

    for(int i = 0; i < LIST_SIZE; i++)
    {
      data = Z_NULL;
      EXPECT_FALSE(sl.remove((TypeParam)(i + LIST_SIZE), data));
      EXPECT_TRUE(sl.remove((TypeParam)i, data));
      EXPECT_EQ((Z_PTR_TYPE)(i + 1) * 8, (Z_PTR_TYPE)data);
      data = Z_NULL;
      EXPECT_FALSE(sl.remove((TypeParam)i, data));
    }
  }
}

REGISTER_TYPED_TEST_CASE_P(skiplistTest, skiplist);
typedef ::testing::Types<Z_U8, Z_U16, Z_U32, Z_U64, Z_I8, Z_I16, Z_I32, Z_I64> skiplistTypes;
INSTANTIATE_TYPED_TEST_CASE_P(skipListTest, skiplistTest, skiplistTypes);

#endif

#if TEST_all || TEST_stdMap
#include <zsystem/core/common/map.h>
template <typename T>
class stdMapTest : public ::testing::Test 
{
public:
protected:
};

#define LIST_SIZE 10

TYPED_TEST_CASE_P(stdMapTest);
TYPED_TEST_P(stdMapTest, stdMap)
{
  {
    zsystem::stdMap<TypeParam, zsystem::mutexLock> smap(LIST_SIZE);
    EXPECT_EQ((Z_U32)LIST_SIZE, smap.getMaxSize());
    EXPECT_EQ((Z_U32)0, smap.getNumber());

    for(int i = 0; i < LIST_SIZE; i++)
    {
#ifdef __DEBUG__
      ASSERT_DEATH(smap.insert((TypeParam)i, (Z_PTR)(i * 8 + 1)), "");
#else
      EXPECT_FALSE(smap.insert((TypeParam)i, (Z_PTR)((i * 8 + 1))));
#endif
      EXPECT_TRUE(smap.insert((TypeParam)i, (Z_PTR)((i + 1) * 8)));
      EXPECT_FALSE(smap.insert((TypeParam)i, (Z_PTR)((i + 1) * 16)));
    }

    Z_PTR data(Z_NULL);
    for(int i = 0; i < LIST_SIZE; i++)
    {
      data = Z_NULL;
      EXPECT_TRUE(smap.lookup((TypeParam)i, data));
      EXPECT_EQ((Z_PTR_TYPE)(i + 1) * 8, (Z_PTR_TYPE)data);
      data = Z_NULL;
      EXPECT_FALSE(smap.lookup((TypeParam)(i + LIST_SIZE), data));
    }

    smap.lock();
    typename zsystem::stdMap<TypeParam, zsystem::mutexLock>::iterator it = smap.begin();
    Z_U32 i = 0;
    TypeParam key((TypeParam)0);
    while(it != smap.end())
    {
      EXPECT_TRUE(smap.get(it, key, data));
      EXPECT_EQ((Z_PTR_TYPE)(i + 1) * 8, (Z_PTR_TYPE)data);
      EXPECT_EQ(i, (Z_U32)key);
      it = smap.next(it);
      i++;
    }
    smap.unlock();

    EXPECT_EQ((Z_U32)LIST_SIZE, i);

    EXPECT_FALSE(smap.get(smap.end(), key, data));

    LOG(INFO) << "stdMap: ";
    LOG(INFO) << smap;

    for(int i = 0; i < LIST_SIZE; i++)
    {
      data = Z_NULL;
      EXPECT_FALSE(smap.remove((TypeParam)(i + LIST_SIZE), data));
      EXPECT_TRUE(smap.remove((TypeParam)i, data));
      EXPECT_EQ((Z_PTR_TYPE)(i + 1) * 8, (Z_PTR_TYPE)data);
      data = Z_NULL;
      EXPECT_FALSE(smap.remove((TypeParam)i, data));
    }
  }
}

REGISTER_TYPED_TEST_CASE_P(stdMapTest, stdMap);
typedef ::testing::Types<Z_U8, Z_U16, Z_U32, Z_U64, Z_I8, Z_I16, Z_I32, Z_I64> stdMapTypes;
INSTANTIATE_TYPED_TEST_CASE_P(stdMapTest, stdMapTest, stdMapTypes);
#endif

#if TEST_all || TEST_malloc
#include <zsystem/core/common/memory.h>
//typedef zsystem::objectAlloc<int, 8> bufferType;
class sampleInt{
public:
  sampleInt(int value):_value(value){}
  ~sampleInt(){}
  int _value;
};

TEST_F(utcase, malloc)
{
  sampleInt* pBuffer = Z_NEW(sampleInt) (100);
  pBuffer->_value = 100;
  EXPECT_EQ(100, pBuffer->_value);
  Z_SAFE_DELETE(pBuffer, ~sampleInt);
  //void* p = malloc(sizeof(sampleInt));
  //sampleInt* pBuffer = new (p) sampleInt(100);
  //pBuffer->~sampleInt();
  //pBuffer->_value = 100;
  //free(p);
}
#endif

#if TEST_all || TEST_timeUtil
#include <zsystem/core/common/time_utils.h>
#include <zsystem/core/threading/thread.h>

TEST_F(utcase, timeUtil)
{
	EXPECT_EQ((Z_I64)8, (Z_I64)zsystem::timeUtil::timeZone());
	zsystem::timeUtil::setTimeZone(12);
	EXPECT_EQ((Z_I64)12, (Z_I64)zsystem::timeUtil::timeZone());
	zsystem::timeUtil::setTimeZone(-12);
	EXPECT_EQ((Z_I64)-12, (Z_I64)zsystem::timeUtil::timeZone());
	zsystem::timeUtil::setTimeZone(0);
	EXPECT_EQ((Z_I64)0, (Z_I64)zsystem::timeUtil::timeZone());
	zsystem::timeUtil::setTimeZone(8);
	EXPECT_EQ((Z_I64)8, (Z_I64)zsystem::timeUtil::timeZone());

	EXPECT_DEATH(zsystem::timeUtil::setTimeZone(13), "");
	EXPECT_DEATH(zsystem::timeUtil::setTimeZone(-13), "");

	time_t t1 = zsystem::timeUtil::now();
	EXPECT_GT(t1, 100000000);
	LOG(INFO) << "Sleep 3 seconds...";
	zsystem::ssleep(3);
	time_t t2;

	t2 = zsystem::timeUtil::getNextPoint(t1, 100000);
	EXPECT_EQ(t1 + 100000, t2);

	t2 = zsystem::timeUtil::getNextPoint(t1 + 10, 100000);
	EXPECT_EQ(t1 + 10, t2);

	t2 = zsystem::timeUtil::getNextPoint(t1, 2);
	EXPECT_GT(t2, t1 + 2);
	EXPECT_EQ(t2, t1 + 4);

	time_t from = 1345392000; // 2012/8/20 00:00:00
	time_t res = zsystem::timeUtil::isAcross(from, from, zsystem::timeUtil::ONE_MINUTE);	// Across minute
	EXPECT_EQ(-1, res);
	res = zsystem::timeUtil::isAcross(from, from + 1, zsystem::timeUtil::ONE_MINUTE);	// Across minute
	EXPECT_EQ(-1, res);
	res = zsystem::timeUtil::isAcross(from - 1, from + 1, zsystem::timeUtil::ONE_MINUTE);	// Across minute
	EXPECT_EQ(from + 1, res);

	time_t testTime = 1345392000; // 2012/8/20 00:00:00
	EXPECT_EQ(testTime, zsystem::timeUtil::getWeekBegin<1>(testTime+12345));
	EXPECT_EQ(testTime + zsystem::timeUtil::ONE_DAY, zsystem::timeUtil::getWeekBegin<2>(testTime+3*zsystem::timeUtil::ONE_DAY + 2345));
	EXPECT_EQ(testTime + zsystem::timeUtil::ONE_DAY*2, zsystem::timeUtil::getWeekBegin<3>(testTime+4*zsystem::timeUtil::ONE_DAY + 2345));
	EXPECT_EQ(testTime + zsystem::timeUtil::ONE_DAY*3, zsystem::timeUtil::getWeekBegin<4>(testTime+5*zsystem::timeUtil::ONE_DAY + 2345));
	EXPECT_EQ(testTime + zsystem::timeUtil::ONE_DAY*4, zsystem::timeUtil::getWeekBegin<5>(testTime+6*zsystem::timeUtil::ONE_DAY + 2345));
	EXPECT_EQ(testTime + zsystem::timeUtil::ONE_DAY*5, zsystem::timeUtil::getWeekBegin<6>(testTime+7*zsystem::timeUtil::ONE_DAY + 2345));
	EXPECT_EQ(testTime - zsystem::timeUtil::ONE_DAY, zsystem::timeUtil::getWeekBegin<7>(testTime + 2345));

	EXPECT_EQ(testTime, zsystem::timeUtil::getDayBegin(testTime+12345));
	EXPECT_EQ(testTime, zsystem::timeUtil::getDayBegin(testTime));
	EXPECT_EQ(testTime, zsystem::timeUtil::getDayBegin(testTime + zsystem::timeUtil::ONE_DAY - 1));

	EXPECT_EQ(testTime, zsystem::timeUtil::getHourBegin(testTime+345));
	EXPECT_EQ(testTime, zsystem::timeUtil::getHourBegin(testTime));
	EXPECT_EQ(testTime, zsystem::timeUtil::getHourBegin(testTime + zsystem::timeUtil::ONE_HOUR - 1));

	EXPECT_EQ(testTime, zsystem::timeUtil::getMinuteBegin(testTime+30));
	EXPECT_EQ(testTime, zsystem::timeUtil::getMinuteBegin(testTime));
	EXPECT_EQ(testTime, zsystem::timeUtil::getMinuteBegin(testTime + zsystem::timeUtil::ONE_MINUTE - 1));

}
#endif

#if TEST_all || TEST_timeUtil_value
#include <zsystem/core/common/time_utils.h>

TEST_F(utcase, timeUtilValue)
{
	time_t from = 1345392000; // 2012/8/20 00:00:00
	Z_U8 hour, minute, second;
	zsystem::timeUtil::getTimeValue(from, hour, minute, second);
	EXPECT_EQ(0, hour);
	EXPECT_EQ(0, minute);
	EXPECT_EQ(0, second);

	zsystem::timeUtil::getTimeValue(from + 8 * zsystem::timeUtil::ONE_HOUR + 41 * zsystem::timeUtil::ONE_MINUTE + 54, hour, minute, second);
	EXPECT_EQ(8, hour);
	EXPECT_EQ(41, minute);
	EXPECT_EQ(54, second);

	zsystem::timeUtil::getTimeValue(from + 23 * zsystem::timeUtil::ONE_HOUR + 59 * zsystem::timeUtil::ONE_MINUTE + 59, hour, minute, second);
	EXPECT_EQ(23, hour);
	EXPECT_EQ(59, minute);
	EXPECT_EQ(59, second);

	zsystem::timeUtil::getTimeValue(from  - 1, hour, minute, second);
	EXPECT_EQ(23, hour);
	EXPECT_EQ(59, minute);
	EXPECT_EQ(59, second);
}
#endif

#if TEST_all || TEST_timeUtil_across
#include <zsystem/core/common/time_utils.h>

TEST_F(utcase, timeUtilAcross)
{
	time_t from = 1345392000; // 2012/8/20 00:00:00
	time_t res = zsystem::timeUtil::isAcross(from, from, zsystem::timeUtil::ONE_MINUTE);	// Across minute
	EXPECT_EQ(-1, res);
	res = zsystem::timeUtil::isAcross(from, from + 1, zsystem::timeUtil::ONE_MINUTE);	// Across minute
	EXPECT_EQ(-1, res);
	res = zsystem::timeUtil::isAcross(from, from + 59, zsystem::timeUtil::ONE_MINUTE);	// Across minute
	EXPECT_EQ(-1, res);
	res = zsystem::timeUtil::isAcross(from, from + 60, zsystem::timeUtil::ONE_MINUTE);	// Across minute
	EXPECT_EQ(from + 60, res);
	res = zsystem::timeUtil::isAcross(from - 1, from, zsystem::timeUtil::ONE_MINUTE);	// Across minute
	EXPECT_EQ(from, res);
	res = zsystem::timeUtil::isAcross(from - 1, from + 1, zsystem::timeUtil::ONE_MINUTE);	// Across minute
	EXPECT_EQ(from + 1, res);
	res = zsystem::timeUtil::isAcross(from - 1, from, zsystem::timeUtil::ONE_MINUTE);	// Across minute
	EXPECT_EQ(from, res);
	res = zsystem::timeUtil::isAcross(from, from, zsystem::timeUtil::ONE_HOUR);	// Across hour
	EXPECT_EQ(-1, res);
	res = zsystem::timeUtil::isAcross(from, from + 1, zsystem::timeUtil::ONE_HOUR);	// Across hour
	EXPECT_EQ(-1, res);
	res = zsystem::timeUtil::isAcross(from, from + 3599, zsystem::timeUtil::ONE_HOUR);	// Across hour
	EXPECT_EQ(-1, res);
	res = zsystem::timeUtil::isAcross(from, from + 3600, zsystem::timeUtil::ONE_HOUR);	// Across hour
	EXPECT_EQ(from + 3600, res);
	res = zsystem::timeUtil::isAcross(from - 1, from, zsystem::timeUtil::ONE_HOUR);	// Across hour
	EXPECT_EQ(from, res);
	res = zsystem::timeUtil::isAcross(from - 1, from + 1, zsystem::timeUtil::ONE_HOUR);	// Across hour
	EXPECT_EQ(from + 1, res);
	res = zsystem::timeUtil::isAcross(from - 1, from + 1000000, zsystem::timeUtil::ONE_HOUR);	// Across hour
	EXPECT_EQ(from + 1000000, res);

	res = zsystem::timeUtil::isAcross(from, from, zsystem::timeUtil::ONE_MINUTE, 30);	// Across half minute
	EXPECT_EQ(-1, res);
	res = zsystem::timeUtil::isAcross(from-1, from, zsystem::timeUtil::ONE_MINUTE, 30);	// Across half minute
	EXPECT_EQ(-1, res);
	res = zsystem::timeUtil::isAcross(from-1, from+1, zsystem::timeUtil::ONE_MINUTE, 30);	// Across half minute
	EXPECT_EQ(-1, res);
	res = zsystem::timeUtil::isAcross(from-30, from+29, zsystem::timeUtil::ONE_MINUTE, 30);	// Across half minute
	EXPECT_EQ(-1, res);
	res = zsystem::timeUtil::isAcross(from+30, from+31, zsystem::timeUtil::ONE_MINUTE, 30);	// Across half minute
	EXPECT_EQ(-1, res);
	res = zsystem::timeUtil::isAcross(from+29, from+30, zsystem::timeUtil::ONE_MINUTE, 30);	// Across half minute
	EXPECT_EQ(from + 30, res);

	res = zsystem::timeUtil::isAcross(from, from, zsystem::timeUtil::ONE_HOUR, 30 * 60);	// Across half hour
	EXPECT_EQ(-1, res);
	res = zsystem::timeUtil::isAcross(from-1, from, zsystem::timeUtil::ONE_HOUR, 30 * 60);	// Across half hour
	EXPECT_EQ(-1, res);
	res = zsystem::timeUtil::isAcross(from-1, from+1, zsystem::timeUtil::ONE_HOUR, 30 * 60);	// Across half hour
	EXPECT_EQ(-1, res);
	res = zsystem::timeUtil::isAcross(from-(30*60), from + (30 * 60) - 1, zsystem::timeUtil::ONE_HOUR, 30 * 60);	// Across half hour
	EXPECT_EQ(-1, res);
	res = zsystem::timeUtil::isAcross(from+(30*60), from + (30 * 60) + 1, zsystem::timeUtil::ONE_HOUR, 30 * 60);	// Across half hour
	EXPECT_EQ(-1, res);
	res = zsystem::timeUtil::isAcross(from+(30*60)-1, from + (30 * 60) + 1, zsystem::timeUtil::ONE_HOUR, 30 * 60);	// Across half hour
	EXPECT_EQ(from + (30 * 60) + 1, res);

	res = zsystem::timeUtil::isAcrossOneDay(from, from);
	EXPECT_EQ(-1, res);
	res = zsystem::timeUtil::isAcrossOneDay(from, from+zsystem::timeUtil::ONE_DAY - 1);
	EXPECT_EQ(-1, res);
	res = zsystem::timeUtil::isAcrossOneDay(from-1, from);
	EXPECT_EQ(from, res);
	res = zsystem::timeUtil::isAcrossOneDay(from-1, from + 10000000);
	EXPECT_EQ(zsystem::timeUtil::getDayBegin(from + 10000000), res);

	res = zsystem::timeUtil::isAcrossOneDay(from, from, 8, 30, 30); // Across 8:30:30
	EXPECT_EQ(-1, res);
	res = zsystem::timeUtil::isAcrossOneDay(from, from + 8 * zsystem::timeUtil::ONE_HOUR + 30 * zsystem::timeUtil::ONE_MINUTE + 30, 8, 30, 30); // Across 8:30:30
	EXPECT_EQ(from + 8 * zsystem::timeUtil::ONE_HOUR + 30 * zsystem::timeUtil::ONE_MINUTE + 30, res);


	res = zsystem::timeUtil::isAcrossOneHour(from, from);
	EXPECT_EQ(-1, res);
	res = zsystem::timeUtil::isAcrossOneHour(from, from+zsystem::timeUtil::ONE_HOUR - 1);
	EXPECT_EQ(-1, res);
	res = zsystem::timeUtil::isAcrossOneHour(from-1, from);
	EXPECT_EQ(from, res);
	res = zsystem::timeUtil::isAcrossOneHour(from-1, from + 10000000);
	EXPECT_EQ(zsystem::timeUtil::getHourBegin(from + 10000000), res);

	res = zsystem::timeUtil::isAcrossOneHour(from, from, 30, 30); // Across 30:30
	EXPECT_EQ(-1, res);
	res = zsystem::timeUtil::isAcrossOneHour(from, from + 30 * zsystem::timeUtil::ONE_MINUTE + 30, 30, 30); // Across 30:30
	EXPECT_EQ(from + 30 * zsystem::timeUtil::ONE_MINUTE + 30, res);

}
#endif

#if TEST_all || TEST_thread
#include <zsystem/core/threading/thread.h>

void doSleep(void* arg)
{
  LOG(INFO) << "a. before sleep";
  zsystem::ssleep(2);
  LOG(INFO) << "b. after sleep";
}

TEST_F(utcase, thread)
{
  LOG(INFO) << "1. before construct";
  zsystem::thread threadSleep(doSleep, NULL);
  LOG(INFO) << "2. after construct";
  ASSERT_TRUE(threadSleep.start());
  LOG(INFO) << "3. after start";
  ASSERT_TRUE(threadSleep.joinable());
  threadSleep.join();
  LOG(INFO) << "4. after join";
}
#endif

#if TEST_all || TEST_conditionVariable
#include <zsystem/core/common/mutex.h>
#include <zsystem/core/threading/thread.h>
void doNotify(void* arg)
{
  zsystem::ssleep(1);
  LOG(INFO) << "a. before notify";
  zsystem::conditionVariable& cond = *(zsystem::conditionVariable*)arg;
  cond.notify_one();
  LOG(INFO) << "b. after notify";
}
TEST_F(utcase, conditionVariable)
{
  zsystem::conditionVariable cond;
  zsystem::mutexLock lock;
  zsystem::mutexGuard guard(lock);
  LOG(INFO) << "1. before construct";
  zsystem::thread threadNotify(doNotify, &cond);
  LOG(INFO) << "2. after construct";
  ASSERT_TRUE(threadNotify.start());
  LOG(INFO) << "3. after start";

  cond.wait(lock);
  LOG(INFO) << "4. after wait";
  threadNotify.join();
  LOG(INFO) << "5. after join";
}
#endif

#if TEST_all || TEST_stdQueue
#include <zsystem/core/common/queue.h>

template <typename T>
class stdQueueTest : public ::testing::Test 
{
protected:
  T _data;
};
TYPED_TEST_CASE_P(stdQueueTest);
TYPED_TEST_P(stdQueueTest, stdQueue)
{
  zsystem::stdQueue<TypeParam> queue(100);
  for(int i = 0; i < 100; i++)
  {
    queue.push((TypeParam)i);
  }
  for(int i = 0; i < 100; i++)
  {
    TypeParam* value = queue.pop();
    ASSERT_TRUE(NULL != value);
    EXPECT_EQ((Z_U64)(*value), (Z_U64)i);
  }
}


REGISTER_TYPED_TEST_CASE_P(stdQueueTest, stdQueue);
typedef ::testing::Types<Z_U8, Z_U16, Z_U32, Z_U64, Z_I8, Z_I16, Z_I32, Z_I64> stdQueueTypes;
INSTANTIATE_TYPED_TEST_CASE_P(StdQueue, stdQueueTest, stdQueueTypes);

#endif

#if TEST_all || TEST_stdList
#include <zsystem/core/common/list.h>

TEST_F(utcase, stdList)
{
  zsystem::stdList<zsystem::mutexLock, Z_I32> list(1000);
  list.pushFront(100);
  EXPECT_EQ(100, list.front());
  EXPECT_EQ(100, list.back());
  EXPECT_EQ(1, list.size());
  Z_I32 data;
  EXPECT_TRUE(list.getAndPopFront(data));
  EXPECT_EQ(100, data);
  EXPECT_EQ(0, list.size());
  EXPECT_FALSE(list.getAndPopFront(data));
  EXPECT_EQ(100, data);

}
#endif

#if TEST_all || TEST_evThread
#include <zsystem/core/threading/evthreadpool.h>
#include <zsystem/core/common/list.h>

zsystem::evThread<zsystem::mutexLock>* g_testEvThread;
#define TEST_ARG 102353
#define TEST_INIT_ARG 5433733

void evThreadInit(Z_PTR thread, Z_PTR arg)
{
  zsystem::evThread<zsystem::mutexLock>* p = (zsystem::evThread<zsystem::mutexLock>*)thread;
  LOG(INFO) << "evThreadInit begin";
  EXPECT_EQ((Z_PTR)g_testEvThread, thread);
  EXPECT_EQ((Z_PTR)TEST_INIT_ARG, arg);
}

void evThreadSleep(Z_PTR thread, Z_PTR arg, Z_PTR initarg)
{
  LOG(INFO) << "a. before sleep";
  zsystem::evThread<zsystem::mutexLock>* p = (zsystem::evThread<zsystem::mutexLock>*)thread;
  ASSERT_TRUE(thread != Z_NULL);
  EXPECT_EQ(1, p->backlog());
  EXPECT_EQ((Z_PTR)TEST_ARG, arg);
  EXPECT_EQ((Z_PTR)TEST_INIT_ARG, initarg);
  zsystem::ssleep(2);
  LOG(INFO) << "b. after sleep";
}

#pragma pack(push,1)
class evThreadCmd{
public:
  Z_PTR arg;
  zsystem::evThreadCallback callback;
  Z_U8 stop;
};
#pragma pack(pop)

TEST_F(utcase, evThread)
{
  evThreadCmd cmd;
  EXPECT_EQ(sizeof(Z_PTR_TYPE) * 2 + 1, sizeof(cmd));

  LOG(INFO) << "1. before construct";
  zsystem::evThread<zsystem::mutexLock> thread(evThreadInit, (Z_PTR)TEST_INIT_ARG);
  g_testEvThread = &thread;
  LOG(INFO) << "2. after construct";
  EXPECT_EQ(0, thread.backlog());
  thread.start();
  EXPECT_EQ(0, thread.backlog());
  LOG(INFO) << "3. after start()";
  thread.defer(evThreadSleep, (Z_PTR)TEST_ARG);
  LOG(INFO) << "4. after defer()";
  zsystem::ssleep(10);
  LOG(INFO) << "5. after sleep()";
  thread.stop();
  LOG(INFO) << "6. after stop()";
}

#define THREAD_PRINT_LOG_TIMES 1000
#define THREAD_NUMBER 3
void evPrintLog(Z_PTR thread, Z_PTR arg, Z_PTR initarg)
{
  for(int i = 0; i < THREAD_PRINT_LOG_TIMES; i++)
  {
    LOG(INFO) << "thread: " << (Z_PTR_TYPE)arg << " - " << i;
  }
}

TEST_F(utcase, evMultiThreadLog)
{
  zsystem::evThread<zsystem::mutexLock>* threads[THREAD_NUMBER];
  for(int i = 0; i < THREAD_NUMBER; i++)
  {
    threads[i] = new zsystem::evThread<zsystem::mutexLock>(Z_NULL, Z_NULL);
    threads[i]->start();
  }
  for(int i = 0; i < THREAD_NUMBER; i++)
  {
    threads[i]->defer(evPrintLog, (Z_PTR)(i + 1));
  }
  zsystem::ssleep(10);
  for(int i = 0; i < THREAD_NUMBER; i++)
  {
    threads[i]->stop();
    delete threads[i];
  }
}

#endif


#if TEST_all || TEST_evThreadPool
#include <zsystem/core/threading/evthreadpool.h>
#include <zsystem/core/common/list.h>

#define THREAD_POOL_TEST_THREAD_NUMBER 3
#define THREAD_POOL_TEST_INIT_ARG 1241515
#define THREAD_POOL_TEST_CALL_TIMES 10000

void evThreadPoolInit(Z_PTR thread, Z_PTR initarg)
{
  LOG(INFO) << "evThreadPoolInit(initarg = " << initarg << ")";
  EXPECT_EQ((Z_PTR_TYPE)THREAD_POOL_TEST_INIT_ARG, (Z_PTR_TYPE)initarg);
}

void evThreadPoolService(Z_PTR thread, Z_PTR arg, Z_PTR initarg)
{
  LOG(INFO) << "evThreadPoolSleep(arg = " << (Z_PTR_TYPE)arg << ", initarg = " << initarg << ")";
  zsystem::evThread<zsystem::mutexLock>* p = (zsystem::evThread<zsystem::mutexLock>*)thread;
  ASSERT_TRUE(thread != Z_NULL);
  EXPECT_EQ((Z_PTR_TYPE)THREAD_POOL_TEST_INIT_ARG, (Z_PTR_TYPE)initarg);
  EXPECT_LT((Z_PTR_TYPE)arg, (Z_PTR_TYPE)THREAD_POOL_TEST_CALL_TIMES);
}

TEST_F(utcase, evThreadPool)
{
  zsystem::evThreadPoolM threadPool(THREAD_POOL_TEST_THREAD_NUMBER, evThreadPoolInit, (Z_PTR)THREAD_POOL_TEST_INIT_ARG);
  ASSERT_TRUE(threadPool.start());

  for(int i = 0; i < THREAD_POOL_TEST_CALL_TIMES; i++)
  {
    threadPool.defer(evThreadPoolService, (Z_PTR)i);
  }
  // Todo: Join
  zsystem::ssleep(10);
  threadPool.stop();
}

#endif

#if TEST_all || TEST_evhtp
#ifdef __LINUX__
#include <event.h>
TEST_F(utcase, evhtp)
{
    event_base         * evbase = NULL;
//    evhtp_t          * htp    = NULL;
    evbase = event_base_new();
//    ASSERT_TRUE(evbase != Z_NULL);
//    htp    = evhtp_new(evbase, NULL);
//    ASSERT_TRUE(htp != Z_NULL);
//    evhtp_use_threads(htp, NULL, 2, NULL);
//    ASSERT_GE(evhtp_bind_socket(htp, "unix:/tmp/core_unittest.sock", 0, 128), 0);
    event_base_loop(evbase, 0);
}
#endif
#endif

#if TEST_all || TEST_tcpsocket
#include <zsystem/core/networking/socket.h>
#include <zsystem/core/networking/packet.h>
#include <zsystem/core/threading/thread.h>
#include <zsystem/core/common/memory.h>
#include <zsystem/core/common/logdump.h>

#define TCP_SOCKET_TEST_ADDRESS "127.0.0.1:12345"
#define SOCKET_TEST_BUFFER_SIZE 65535

Z_BOOL tcpsocket_test_exit = Z_FALSE;
zsystem::tcpSocket* serverTcpSocket[32] = {Z_NULL};
Z_I32 serverTcpIndex(0);

void onServerSocketAccpet(Z_PTR arg)
{
  Z_DUMP_LOG( "onServerSocketAccept() begin" );
  zsystem::tcpSocket& serverSocket = *((zsystem::tcpSocket*)arg);
  Z_SOCKET_HANDLE socket;
  Z_SOCKET_ADDRESS address;
  while ( !tcpsocket_test_exit )
  {
    Z_DUMP("to accept");
    google::FlushLogFiles(INFO);
    if ( serverSocket.accept(socket, address) )
    {
      Z_DUMP("accept ok");
      serverTcpSocket[serverTcpIndex] = Z_NEW(zsystem::tcpSocket) (socket, address, 1024, 1024, Z_TRUE, 0);
      serverTcpIndex++;
    }
    else
    {
      Z_DUMP("accept error");
      LOG(WARNING) << "onServerSocketAccept accept error";
      break;
    }
  };
  Z_DUMP_LOG( "Exit onServerSocketAccept");
}

const Z_BOOL receive(zsystem::tcpSocket& socket, char* const buffer, const Z_U16 len)
{
  Z_I32 received(0);
  Z_I32 remain(len);
  while ( remain > 0 )
  {
    received = socket.receive(buffer + len - remain, remain);
    if ( received < 0 )
    {
      if ( socket.isEAgain() )
      {
        Z_PAUSE();
        continue;
      }
      LOG(WARNING) << "receive error 1";
      return Z_FALSE;
    }
    else if ( received == 0 )
    {
      LOG(WARNING) << "receive error 2";
      return Z_FALSE;
    }
    remain -= received;
    if ( remain < 0 )
    {
      LOG(WARNING) << "receive error 3";
      return Z_FALSE;
    }

    Z_DUMP("received " << received << " bytes, remain " << remain << " bytes");
  }
  return Z_TRUE;
}

const Z_BOOL send(zsystem::tcpSocket& socket, char* const buffer, const Z_U16 len)
{
  Z_I32 sent(0);
  Z_I32 remain(len);
  while ( remain > 0 )
  {
    sent = socket.send(buffer + len - remain, remain);
    if ( sent < 0 )
    {
      if ( socket.isEAgain() )
      {
        Z_PAUSE();
        continue;
      }
      LOG(WARNING) << "send error 1";
      return Z_FALSE;
    }
    else if ( sent == 0 )
    {
      LOG(WARNING) << "sent error 2";
      return Z_FALSE;
    }
    remain -= sent;
    if ( remain < 0 )
    {
      LOG(WARNING) << "sent error 3";
      return Z_FALSE;
    }

    Z_DUMP("sent " << sent << " bytes, remain " << remain << " bytes");
  }
  return Z_TRUE;
}

void onServerReceive(Z_PTR arg)
{
  Z_DUMP_LOG( "onServerReceive() begin" );
  zsystem::tcpSocket& serverSocket = *((zsystem::tcpSocket*)arg);


  while(!tcpsocket_test_exit)
  {
    for(int i = 0; i < serverTcpIndex; i++)
    {
      zsystem::packet data;
      if ( !receive(*serverTcpSocket[i], data.getHeadData(), Z_PACKET_HEAD_SIZE) )
      {
        LOG(WARNING) << "onServerReceive receive head error";
        break;
      }

      if ( !data.allocByHead() )
      {
        LOG(WARNING) << "onServerReceive check head or alloc data error";
        break;
      }

      if ( !receive(*serverTcpSocket[i], data.getData(), data.getDataSize()) )
      {
        LOG(WARNING) << "onServerReceive receive data error";
        break;
      }

      // echo
      if ( !send(*serverTcpSocket[i], data.getHeadData(), Z_PACKET_HEAD_SIZE) )
      {
        LOG(WARNING) << "onServerReceive send head error";
        break;
      }
      if ( !send(*serverTcpSocket[i], data.getData(), data.getDataSize()) )
      {
        LOG(WARNING) << "onServerReceive send data error";
        break;
      }
    }
    zsystem::ssleep(1);
  }

  for(int i = 0; i < serverTcpIndex; i++)
  {
    serverTcpSocket[i]->close();
    Z_SAFE_DELETE(serverTcpSocket[i], ~tcpSocket);
  }
  Z_DUMP_LOG("Exit onServerReceive");
}

TEST_F(utcase, packet)
{
  EXPECT_EQ(8, sizeof(zsystem::packet::head));
  zsystem::packet::head h;
  Z_PTR_TYPE begin = (Z_PTR_TYPE)&(h.seqId);
  EXPECT_EQ(begin + 2, (Z_PTR_TYPE)&(h.msgId));
  EXPECT_EQ(begin + 4, (Z_PTR_TYPE)&(h.dataSize));
  EXPECT_EQ(begin + 6, (Z_PTR_TYPE)&(h.headTail));

  zsystem::packet p;
  p.setSeqId(1);
  p.setMsgId(2);
  p.setDataSize(8);

  EXPECT_EQ(1, p.getSeqId());
  EXPECT_EQ(2, p.getMsgId());
  EXPECT_EQ(8, p.getDataSize());
  EXPECT_EQ(8 + 8, p.getPacketSize());

  ASSERT_TRUE(p.getData() != Z_NULL);
  ASSERT_TRUE(p.getHeadData() != Z_NULL);
}


TEST_F(utcase, tcpsocket)
{
  // Start server
  zsystem::tcpSocket serverSocket(1024, 1024, Z_TRUE, 60);
  Z_DUMP("serverSocket to bind");
  ASSERT_TRUE(serverSocket.bind(TCP_SOCKET_TEST_ADDRESS));
  Z_DUMP("serverSocket to listen");
  ASSERT_TRUE(serverSocket.listen(100));

  zsystem::thread acceptThread(onServerSocketAccpet, &serverSocket);
  Z_DUMP("acceptThread to start");
  ASSERT_TRUE(acceptThread.start());

  zsystem::thread serverConnectionThread(onServerReceive, &serverSocket);
  Z_DUMP("serverConnectionThread to listen");
  ASSERT_TRUE(serverConnectionThread.start());

  // Start client
  zsystem::tcpSocket clientSocket(1024, 1024, Z_FALSE, 60);

  Z_DUMP("clientSocket to connect");
  ASSERT_TRUE(clientSocket.connect(TCP_SOCKET_TEST_ADDRESS));
  google::FlushLogFiles(INFO);


  char testBuffer[SOCKET_TEST_BUFFER_SIZE]={0};
  for ( int i = 0; i < SOCKET_TEST_BUFFER_SIZE; i++ )
  {
    testBuffer[i] = (char)(i % 256);
  }

  zsystem::packet sendPack(0, 1, SOCKET_TEST_BUFFER_SIZE);

  zsystem::packet* receivePack;
  Z_DUMP("Begin send and receive");
  google::FlushLogFiles(INFO);

  for(int i = 0; i < 5; i++)
  {
    Z_DUMP("client send " << i);
    sendPack.setSeqId(i+1);
    char* dataPoint = sendPack.getData();
    memcpy(dataPoint, testBuffer, SOCKET_TEST_BUFFER_SIZE);
//    *((int*)sendPack.getData()) = i;

    ASSERT_TRUE(send(clientSocket, sendPack.getHeadData(), Z_PACKET_HEAD_SIZE));
    ASSERT_TRUE(send(clientSocket, sendPack.getData(), SOCKET_TEST_BUFFER_SIZE));

    receivePack = Z_NEW(zsystem::packet)();

    ASSERT_TRUE(receive(clientSocket, receivePack->getHeadData(), Z_PACKET_HEAD_SIZE));
    ASSERT_TRUE(receivePack->isHeadValid());

    ASSERT_EQ(SOCKET_TEST_BUFFER_SIZE, receivePack->getDataSize());
    ASSERT_TRUE(receivePack->allocData());
    ASSERT_TRUE(receive(clientSocket, receivePack->getData(), SOCKET_TEST_BUFFER_SIZE));
    char* echoBuffer = receivePack->getData();
    for ( int i = 0; i < SOCKET_TEST_BUFFER_SIZE; i++ )
    {
      EXPECT_EQ((char)(i % 256), echoBuffer[i]);
    }
  }

  // Close connection
  Z_DUMP("to exit");
  tcpsocket_test_exit = Z_TRUE;
  serverSocket.close();
  clientSocket.close();
  acceptThread.join();
  Z_DUMP("acceptionThread join ok");
  serverConnectionThread.join();
  Z_DUMP("serverConnectionThread join ok");
  Z_DUMP("sockets closed");
}
#endif

#if TEST_all || TEST_tcpconnection
#include <zsystem/core/networking/connection.h>
#include <zsystem/core/threading/thread.h>
#include <zsystem/core/common/memory.h>
#include <zsystem/core/common/logdump.h>

#define TCP_CONNECTION_TEST_ADDRESS "127.0.0.1:12345"
#define TCP_CONNECTION_TEST_BUFFER_SIZE 65535

Z_BOOL tcpclient_test_exit = Z_FALSE;
zsystem::tcpSocket* serverConnectionSocket[32] = {Z_NULL};
Z_I32 serverConnectionIndex(0);
//
//void onServerConnectionAccpet(Z_PTR arg)
//{
//  Z_DUMP_LOG( "onServerSocketAccept() begin" );
//  zsystem::tcpSocket& serverSocket = *((zsystem::tcpSocket*)arg);
//  Z_SOCKET_HANDLE socket;
//  Z_SOCKET_ADDRESS address;
//  while ( !tcpclient_test_exit )
//  {
//    Z_DUMP("to accept");
//    if ( serverSocket.accept(socket, address) )
//    {
//      Z_DUMP("accept ok");
//      serverConnectionSocket[serverConnectionIndex] = Z_NEW(zsystem::tcpSocket) (socket, address, 1024, 1024, Z_TRUE, 0);
//      serverConnectionIndex++;
//    }
//    else
//    {
//      Z_DUMP("accept error");
//      LOG(WARNING) << "onServerSocketAccept accept error";
//      break;
//    }
//  };
//  Z_DUMP_LOG( "Exit onServerSocketAccept");
//}
//
//const Z_BOOL receive(zsystem::tcpSocket& socket, char* const buffer, const Z_U16 len)
//{
//  Z_I32 received(0);
//  Z_I32 remain(len);
//  while ( remain > 0 )
//  {
//    received = socket.receive(buffer + len - remain, remain);
//    if ( received < 0 )
//    {
//      if ( socket.isEAgain() )
//      {
//        Z_PAUSE();
//        continue;
//      }
//      LOG(WARNING) << "receive error 1";
//      return Z_FALSE;
//    }
//    else if ( received == 0 )
//    {
//      LOG(WARNING) << "receive error 2";
//      return Z_FALSE;
//    }
//    remain -= received;
//    if ( remain < 0 )
//    {
//      LOG(WARNING) << "receive error 3";
//      return Z_FALSE;
//    }
//
//    Z_DUMP("received " << received << " bytes, remain " << remain << " bytes");
//  }
//  return Z_TRUE;
//}
//
//const Z_BOOL send(zsystem::tcpSocket& socket, char* const buffer, const Z_U16 len)
//{
//  Z_I32 sent(0);
//  Z_I32 remain(len);
//  while ( remain > 0 )
//  {
//    sent = socket.send(buffer + len - remain, remain);
//    if ( sent < 0 )
//    {
//      if ( socket.isEAgain() )
//      {
//        Z_PAUSE();
//        continue;
//      }
//      LOG(WARNING) << "send error 1";
//      return Z_FALSE;
//    }
//    else if ( sent == 0 )
//    {
//      LOG(WARNING) << "sent error 2";
//      return Z_FALSE;
//    }
//    remain -= sent;
//    if ( remain < 0 )
//    {
//      LOG(WARNING) << "sent error 3";
//      return Z_FALSE;
//    }
//
//    Z_DUMP("sent " << sent << " bytes, remain " << remain << " bytes");
//  }
//  return Z_TRUE;
//}

//void onServerReceive(Z_PTR arg)
//{
//  Z_DUMP_LOG( "onServerReceive() begin" );
//  zsystem::tcpSocket& serverSocket = *((zsystem::tcpSocket*)arg);
//
//
//  while(!tcpclient_test_exit)
//  {
//    for(int i = 0; i < serverConnectionIndex; i++)
//    {
//      zsystem::packet data;
//      if ( !receive(*serverConnectionSocket[i], data.getHeadData(), Z_PACKET_HEAD_SIZE) )
//      {
//        LOG(WARNING) << "onServerReceive receive head error";
//        break;
//      }
//
//      if ( !data.allocByHead() )
//      {
//        LOG(WARNING) << "onServerReceive check head or alloc data error";
//        break;
//      }
//
//      if ( !receive(*serverConnectionSocket[i], data.getData(), data.getDataSize()) )
//      {
//        LOG(WARNING) << "onServerReceive receive data error";
//        break;
//      }
//
//      // echo
//      if ( !send(*serverConnectionSocket[i], data.getHeadData(), Z_PACKET_HEAD_SIZE) )
//      {
//        LOG(WARNING) << "onServerReceive send head error";
//        break;
//      }
//      if ( !send(*serverConnectionSocket[i], data.getData(), data.getDataSize()) )
//      {
//        LOG(WARNING) << "onServerReceive send data error";
//        break;
//      }
//    }
//    zsystem::ssleep(1);
//  }
//
//  for(int i = 0; i < serverConnectionIndex; i++)
//  {
//    serverConnectionSocket[i]->close();
//    Z_SAFE_DELETE(serverConnectionSocket[i], ~tcpSocket);
//  }
//  Z_DUMP_LOG("Exit onServerReceive");
//}

void onClientReceivedMessage1(zsystem::listenerContainer* container, zsystem::tcpConnection* connection, const Z_U16 seqId, const Z_U16 msgId, char* const buffer, const Z_U16 len)
{
  Z_DUMP_LOG("onClientReceivedMessage1( seqId = " << seqId << ")");
}

void onServerReceivedMessage1(zsystem::listenerContainer* container, zsystem::tcpConnection* connection, const Z_U16 seqId, const Z_U16 msgId, char* const buffer, const Z_U16 len)
{
  Z_DUMP_LOG("onServerReceivedMessage1( seqId = " << seqId << ")");
}

void defaultListener(zsystem::listenerContainer* container, zsystem::tcpConnection* connection, const Z_U16 seqId, const Z_U16 msgId, char* const buffer, const Z_U16 len)
{
  Z_DUMP_LOG("defaultListener( seqId = " << seqId << ", " << msgId << ")");
}

Z_BOOL testTcpClientConnected(Z_FALSE);
class testTcpClient : public zsystem::tcpClient {
public:
  testTcpClient(const Z_I32 sendBufferSize, const Z_I32 recieveBufferSize)
  :zsystem::tcpClient(defaultListener, sendBufferSize, recieveBufferSize){
  }
protected:
  void onConnected(zsystem::tcpConnection* connection)
  {
    Z_DUMP_LOG("Client connected!");
    testTcpClientConnected = Z_TRUE;
  }
  void onDisconnected(zsystem::tcpConnection* connection)
  {
    Z_DUMP_LOG("Client disconnected!");
    testTcpClientConnected = Z_FALSE;
  }
};

class testTcpServer : public zsystem::tcpServer {
public:
  testTcpServer(const char* bindAddress, const Z_I32 sendBufferSize, const Z_I32 recieveBufferSize, const Z_I32 keepAliveInterval, const Z_U16 threads, const Z_I32 backlog)
  :zsystem::tcpServer(defaultListener, bindAddress, sendBufferSize, recieveBufferSize, keepAliveInterval, threads, backlog){
  }
protected:
  void onConnected(zsystem::tcpConnection* connection)
  {
    Z_DUMP_LOG("Server connection connected!");
  }
  void onDisconnected(zsystem::tcpConnection* connection)
  {
    Z_DUMP_LOG("Server connection disconnected!");
  }
};

TEST_F(utcase, tcpconnection)
{
  // Start server
  testTcpServer server(TCP_CONNECTION_TEST_ADDRESS, 1024, 1024, 60, 4, 100);
  ASSERT_TRUE(server.addListener(1, onServerReceivedMessage1));
  ASSERT_TRUE(server.start());

  // Start client
  testTcpClient client(1024, 1024);

  Z_DUMP("clientSocket to connect");
  ASSERT_TRUE(client.connect(TCP_CONNECTION_TEST_ADDRESS));
  google::FlushLogFiles(INFO);
  char testBuffer[TCP_CONNECTION_TEST_BUFFER_SIZE]={0};
  for ( int i = 0; i < TCP_CONNECTION_TEST_BUFFER_SIZE; i++ )
  {
    testBuffer[i] = (char)(i % 256);
  }

  Z_DUMP_LOG("Waiting connect...");
  google::FlushLogFiles(INFO);

  for ( int i = 0 ; i < 5; i++ )
  {
    if ( testTcpClientConnected )
    {
      break;
    }
    zsystem::ssleep(1);
  }

  Z_DUMP_LOG("Begin send and receive");
  google::FlushLogFiles(INFO);

  if ( testTcpClientConnected )
  {
    client.addListener(1, onClientReceivedMessage1);
    for(int i = 0; i < 5; i++)
    {
      Z_DUMP("client send " << i);
      ASSERT_TRUE(client.send(1, testBuffer, TCP_CONNECTION_TEST_BUFFER_SIZE));
      zsystem::ssleep(1);
    }
  }
  else
  {
    Z_DUMP("Connected failed!");
  }

  // Close connection
  client.close();
  Z_DUMP("to exit");
  server.stop();
  Z_DUMP("server.stop ok");
  Z_DUMP("client.close ok");
  zsystem::ssleep(1);
}
#endif

#if TEST_all || TEST_repidjson

#include <zsystem/core/json/rapidjson.h>

const char* json_test_string = "1234567890asdfgASDFG";
char json_test_string_chinese[] = 
{
0XE4u, 0XB8u, 0X80u, 
0XE4u, 0XBAu, 0X8Cu, 
0XE4u, 0XB8u, 0X89u,
0XE5u, 0X9Bu, 0X9Bu,
0XE4u, 0XBAu, 0X94u
};
char json_test_utf8_chinese[] = {(char)228, (char)184, (char)173};
TEST_F(utcase, repidjson_chinese)
{
  const char* chinese_json = "{\"chinese\":\"\\u4E2D\"}";
  zsystem::RJsonDocument document;
  ASSERT_FALSE(document.Parse<0>(chinese_json).HasParseError());
  EXPECT_TRUE(document.HasMember("chinese"));
  LOG(INFO) << document["chinese"].GetString() << std::endl;
  EXPECT_STREQ(json_test_utf8_chinese, document["chinese"].GetString());

  zsystem::RJsonStringBuffer s(0, 65535);
  zsystem::RJsonStringWrite writer(s);
  document.Accept(writer);
  LOG(INFO) << "json size: " << s.GetSize() << " bytes";
  LOG(INFO) << s.GetString();
  google::FlushLogFiles(INFO);
  EXPECT_STREQ(chinese_json, s.GetString());

}

struct json_test_person{
  Z_I64 id;
  int sex;
  const char* name;
  const char* mobile;
};

json_test_person json_test_people[] = 
{
  { 1, 1, "zhangpeihao", "1302012XXXX" },
  { 2, 2, "Avalokitesvara", "123454321" },
  { 3, 3, "tathagata", "987656789" }
};

TEST_F(utcase, repidjson)
{
  zsystem::RJsonDocument document;
  document.SetObject();
//  ASSERT_FALSE(document.Parse<0>("{}").HasParseError());

  // int
  document.AddMember<int>("int_1", 1, document.GetAllocator());
  document.AddMember<int>("int_0", 0, document.GetAllocator());
  document.AddMember<int>("int_-1", -1, document.GetAllocator());
  document.AddMember<int>("int_min", int(-2147483648LL), document.GetAllocator());
  document.AddMember<int>("int_max", 2147483647, document.GetAllocator());

  // int64
  document.AddMember<Z_I64>("int64_1", (Z_I64)1, document.GetAllocator());
  document.AddMember<Z_I64>("int64_0", (Z_I64)0, document.GetAllocator());
  document.AddMember<Z_I64>("int64_-1", (Z_I64)-1, document.GetAllocator());
  document.AddMember<Z_I64>("int64_min", (Z_I64)0X1000000000000000LL, document.GetAllocator());
  document.AddMember<Z_I64>("int64_max", (Z_I64)9223372036854775807LL, document.GetAllocator());

  // float
  document.AddMember<float>("float_1", 1.0f, document.GetAllocator());
  document.AddMember<float>("float_0", 0.0f, document.GetAllocator());
  document.AddMember<float>("float_-1", -1.0f, document.GetAllocator());
  document.AddMember<float>("float_small", 0.1234567890123456789f, document.GetAllocator());
  document.AddMember<float>("float_big", 1234567890123456789.0f, document.GetAllocator());

  // string
  zsystem::RJsonAddString string, string_chinese;
  string.AddStringMember(document, "string", json_test_string, document.GetAllocator());
  string_chinese.AddStringMember(document, "string_chinese", json_test_string_chinese, document.GetAllocator());

  //zsystem::RJsonValue string, stringChinese;
  //string.SetString(json_test_string, strlen(json_test_string), document.GetAllocator());
  //stringChinese.SetString(json_test_string_chinese, strlen(json_test_string_chinese), document.GetAllocator());
  //document.AddMember("string", string, document.GetAllocator());
  //document.AddMember("string_chinese", stringChinese, document.GetAllocator());

  // array
  zsystem::RJsonValue people(rapidjson::kArrayType);
  people.Reserve(4, document.GetAllocator());
  int peopleNumber = sizeof(json_test_people) / sizeof(json_test_person);
  for ( int i = 0; i < peopleNumber; i++ )
  {
    zsystem::RJsonValue person;
    json_test_person& personData = json_test_people[i];
    person.SetObject();
    person.AddMember<Z_I64>("id", personData.id, document.GetAllocator());
    person.AddMember<int>("sex", personData.sex, document.GetAllocator());
    {
      zsystem::RJsonValue personString;
      personString.SetString(personData.name, strlen(personData.name), document.GetAllocator());
      person.AddMember("name",personString, document.GetAllocator());
    }
    {
      zsystem::RJsonValue personString;
      personString.SetString(personData.mobile, strlen(personData.mobile), document.GetAllocator());
      person.AddMember("mobile",personString, document.GetAllocator());
    }
    people.PushBack(person, document.GetAllocator());
  }


  document.AddMember("people", people, document.GetAllocator());

  zsystem::RJsonStringBuffer s(0, 65535);
  zsystem::RJsonStringWrite writer(s);
  document.Accept(writer);
  LOG(INFO) << "json size: " << s.GetSize() << " bytes";
  LOG(INFO) << s.GetString();
  google::FlushLogFiles(INFO);

  std::stringstream ss;
  ss << s.GetString();

  zsystem::RJsonDocument checkDoc;
  ASSERT_FALSE(checkDoc.Parse<0>(ss.str().c_str()).HasParseError());

#define CHECK_INT(NAME, VALUE)             \
  EXPECT_TRUE(checkDoc.HasMember(NAME));   \
  EXPECT_TRUE(checkDoc[NAME].IsNumber());  \
  EXPECT_TRUE(checkDoc[NAME].IsInt());     \
  EXPECT_EQ(VALUE, checkDoc[NAME].GetInt());

  CHECK_INT("int_1", 1)
  CHECK_INT("int_0", 0)
  CHECK_INT("int_-1", -1)
  CHECK_INT("int_min", int(-2147483648LL))
  CHECK_INT("int_max", 2147483647)

#define CHECK_STRING(NAME, VALUE)             \
  EXPECT_TRUE(checkDoc.HasMember(NAME));   \
  EXPECT_TRUE(checkDoc[NAME].IsString());  \
  EXPECT_STREQ(VALUE, checkDoc[NAME].GetString());

  CHECK_STRING("string", json_test_string);
  CHECK_STRING("string_chinese", json_test_string_chinese);

  EXPECT_TRUE(checkDoc.HasMember("people"));
  zsystem::RJsonValue& checkPeople = checkDoc["people"];
  EXPECT_TRUE(checkPeople.IsArray());
  EXPECT_EQ(peopleNumber, checkPeople.Size());

#define CHECK_PERSION(CHECKPERSON, PERSONDATA)             \
  EXPECT_TRUE(CHECKPERSON.HasMember("id"));   \
  EXPECT_TRUE(CHECKPERSON.HasMember("sex"));   \
  EXPECT_TRUE(CHECKPERSON.HasMember("name"));   \
  EXPECT_TRUE(CHECKPERSON.HasMember("mobile"));   \
  EXPECT_TRUE(CHECKPERSON["id"].IsInt64());  \
  EXPECT_TRUE(CHECKPERSON["sex"].IsInt());  \
  EXPECT_TRUE(CHECKPERSON["name"].IsString());  \
  EXPECT_TRUE(CHECKPERSON["mobile"].IsString());  \
  EXPECT_EQ(PERSONDATA.id, CHECKPERSON["id"].GetInt64()); \
  EXPECT_EQ(PERSONDATA.sex, CHECKPERSON["sex"].GetInt()); \
  EXPECT_STREQ(PERSONDATA.name, CHECKPERSON["name"].GetString()); \
  EXPECT_STREQ(PERSONDATA.mobile, CHECKPERSON["mobile"].GetString());

  for ( rapidjson::SizeType i = 0; i < checkPeople.Size() && i < rapidjson::SizeType(peopleNumber); i++ )
  {
    zsystem::RJsonValue& checkPerson = checkPeople[i];
    json_test_person& personData = json_test_people[i];
    CHECK_PERSION(checkPerson, personData)
  }

}

TEST_F(utcase, embed_json)
{
  const char* TEST_EMBED_JSON="{\"id\":1,\"props\":[{\"1003\":2},{\"1004\":\"test\"}]}";

  zsystem::RJsonDocument document;
  document.SetObject();

  zsystem::RJsonAddString embedText;
  zsystem::RJsonAddEmbeded embedObject;
  embedText.AddStringMember(document, "embedText", TEST_EMBED_JSON, document.GetAllocator());
  embedObject.AddEmbededMember(document, "embedObject", TEST_EMBED_JSON, document.GetAllocator());

  //zsystem::RJsonValue embedString;
  //embedString.SetString(TEST_EMBED_JSON, strlen(TEST_EMBED_JSON), document.GetAllocator());
  //document.AddMember("embedText", embedString, document.GetAllocator());

  //zsystem::RJsonDocument embedDocument;
  //ASSERT_FALSE(embedDocument.Parse<0>(TEST_EMBED_JSON).HasParseError());
  //zsystem::RJsonValue& embedValue = embedDocument;
  //document.AddMember("embedObject", embedValue, document.GetAllocator());

  zsystem::RJsonStringBuffer s(0, 65535);
  zsystem::RJsonStringWrite writer(s);
  document.Accept(writer);
  LOG(INFO) << "json size: " << s.GetSize() << " bytes";
  LOG(INFO) << s.GetString();
  google::FlushLogFiles(INFO);


}
#endif

#if TEST_all || TEST_gflags
#include <gflags/gflags.h>

DEFINE_bool(autorun, false, "Auto run");
DEFINE_bool(default_bool, true, "Default boolean test");
DEFINE_int32(threads, 10, "Thread number");
DEFINE_int32(default_int, 1000, "Default int test");
DEFINE_double(somerate, 0.3, "Some rate in float");
DEFINE_double(default_double, 0.12345, "Default float test");
DEFINE_string(bindAddress, "127.0.0.1:12345", "The address to bind");
DEFINE_string(default_string, "foobar", "Default string test");
DEFINE_int32(intInFile, 0, "Int in config file");

TEST_F(utcase, gflags)
{
  EXPECT_TRUE(FLAGS_autorun);
  EXPECT_EQ(1000, FLAGS_threads);
  EXPECT_DOUBLE_EQ(0.4321, FLAGS_somerate);
  EXPECT_STREQ("localhost:54321", FLAGS_bindAddress.c_str());

  EXPECT_TRUE(FLAGS_default_bool);
  EXPECT_EQ(1000, FLAGS_default_int);
  EXPECT_DOUBLE_EQ(0.12345, FLAGS_default_double);
  EXPECT_STREQ("foobar", FLAGS_default_string.c_str());

  EXPECT_EQ(4321, FLAGS_intInFile);

}

#endif

#if TEST_all || TEST_lua
#include <zsystem\core\lua\luaPacket.h>

TEST_F(utcase, gflags)
{
  zsystem::luaPacket lua;
#ifdef __WIN32__
  char* luaFilePath = "..\\..\\unittest\\core\\luascripts";
#else
  char* luaFilePath = "./luascripts";
#endif
  ASSERT_TRUE(lua.init(luaFilePath));
}

#endif

int main(int argc, char **argv) 
{
  google::InitGoogleLogging(argv[0]);

#if TEST_all || TEST_gflags
  std::string usage("core_unittest <flags>");
  std::string version("0.0.1");
  google::SetUsageMessage(usage);
  google::SetVersionString(version);
  google::ParseCommandLineFlags(&argc, &argv, true);
#endif

#ifdef __WIN32__
    google::SetLogDestination(INFO, "..\\..\\..\\logs\\INFO_");
    google::SetLogDestination(WARNING, "..\\..\\..\\logs\\WARNING_");
    google::SetLogDestination(ERROR, "..\\..\\..\\logs\\ERROR_");

    WSADATA wsaData;  
    DWORD Ret;  
    if ((Ret = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0)  {  
      printf("WSAStartup failed with error %d\n", Ret);  
      return -1;  
    }
#if TEST_all || TEST_tcpconnection
    CHECK_EQ(evthread_use_windows_threads(), 0);
#endif
#endif
#ifdef __LINUX__
    google::SetLogDestination(INFO, "/tmp/INFO_");
    google::SetLogDestination(WARNING, "/tmp/WARNING_");
    google::SetLogDestination(ERROR, "/tmp/ERROR_");
#if TEST_all || TEST_tcpconnection
    CHECK_EQ(evthread_use_pthreads(), 0);
#endif
#endif

  ::testing::InitGoogleTest(&argc, argv);


  int r = RUN_ALL_TESTS();
#ifdef __WIN32__
  getchar();
  WSACleanup();  
#endif

  google::ShutdownGoogleLogging();

  return r;
}

